#include <vector>
#include <fstream>
#include <sstream>
#include "LevenshteinAlgorithm.h"

unsigned int LevenshteinAlgorithm::getLevDist(const std::string& s1,
					      const std::string& s2) const {
    size_t n = s1.length();
    size_t m = s2.length();
    if (!n) return (unsigned int)m;
    if (!m) return (unsigned int)n;

    std::vector<std::vector<unsigned int>> c(2, std::vector<unsigned int>(m + 1, 0));

    for (size_t i = 1; i <= m; ++i) {
        c[0][i] = i;
    }

    for (size_t i = 1; i <= n; ++i) {
        c[1][0] = i;

        for (size_t j = 1; j <= m; ++j) {
            unsigned int cost = s1[i - 1] ^ s2[j - 1] ? 1 : 0;
            c[1][j] = std::min(c[1][j - 1] + 1, c[0][j] + 1);
            c[1][j] = std::min(c[1][j], c[0][j - 1] + cost);
        }

        c[0].swap(c[1]);
    }

    return c[0][m];
}

double LevenshteinAlgorithm::getSim(const FilePairType& file_pair) const {

    auto first_filename = file_pair.first->filename;
    auto second_filename = file_pair.second->filename;
    std::ifstream first_stream(first_filename.data(), std::ifstream::in);
    std::stringstream first_buffer;
    first_buffer << first_stream.rdbuf();
    
    std::ifstream second_stream(second_filename.data(), std::ifstream::in);
    std::stringstream second_buffer;
    second_buffer << second_stream.rdbuf();
    
    std::string first_string = first_buffer.str();
    std::string second_string = second_buffer.str();
    size_t n = first_string.length();
    size_t m = second_string.length();
    auto max = std::max(n, m);

    if (!max) return 1.0;
    double dist = getLevDist(first_string, second_string);

    return 1.0 - dist / max;
}
